å®å šã§ä¿¡é Œæ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã«ãå ¥åãµãã¿ã€ãºã®ããã®TypeScriptåãã¿ãŒã³ãæ¢ããŸããXSSãã€ã³ãžã§ã¯ã·ã§ã³æ»æãªã©ã®äžè¬çãªè匱æ§ãé²ãæ¹æ³ãåŠã³ãŸãã
TypeScriptã»ãã¥ãªãã£ïŒå ç¢ãªã¢ããªã±ãŒã·ã§ã³ã®ããã®å ¥åãµãã¿ã€ãºåãã¿ãŒã³
仿¥ã®çžäºæ¥ç¶ãããäžçã§ã¯ãå®å šã§ä¿¡é Œæ§ã®é«ãWebã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããšãæãéèŠã§ãããµã€ããŒè åšã®å·§åŠåãé²ãã«ã€ããŠãéçºè ã¯æ©å¯ããŒã¿ãä¿è·ããæªæã®ããæ»æãé²ãããã«å ç¢ãªã»ãã¥ãªãã£å¯Ÿçãè¬ããå¿ èŠããããŸããTypeScriptã¯ã匷åãªåä»ãã·ã¹ãã ã«ãããç¹ã«ãå ¥åãµãã¿ã€ãºåãã¿ãŒã³ããéããŠãã¢ããªã±ãŒã·ã§ã³ã®ã»ãã¥ãªãã£ã匷åãã匷åãªããŒã«ãæäŸããŸãããã®å æ¬çãªã¬ã€ãã§ã¯ãå ¥åãµãã¿ã€ãºã®ããã®ããŸããŸãªTypeScriptåãã¿ãŒã³ãæ¢æ±ããããå®å šã§å埩åã®ããã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããããã«ããŸãã
å ¥åãµãã¿ã€ãºãéèŠãªçç±
å ¥åãµãã¿ã€ãºãšã¯ããŠãŒã¶ãŒãæäŸããããŒã¿ãã¯ãªãŒã³ã¢ãããŸãã¯å€æŽããã¢ããªã±ãŒã·ã§ã³ããŠãŒã¶ãŒã«æå®³ãäžããã®ãé²ãããã»ã¹ã§ãããã©ãŒã éä¿¡ãAPIãªã¯ãšã¹ãããŸãã¯ãã®ä»ã®å€éšãœãŒã¹ããã®ä¿¡é Œã§ããªãããŒã¿ã¯ã次ã®ãããªè匱æ§ãåŒãèµ·ããå¯èœæ§ããããŸãã
- ã¯ãã¹ãµã€ãã¹ã¯ãªããã£ã³ã° (XSS)ïŒæ»æè ãä»ã®ãŠãŒã¶ãŒãé²èЧããWebããŒãžã«æªæã®ããã¹ã¯ãªãããæ³šå ¥ããŸãã
- SQLã€ã³ãžã§ã¯ã·ã§ã³ïŒæ»æè ãæªæã®ããSQLã³ãŒããããŒã¿ããŒã¹ã¯ãšãªã«æ¿å ¥ããŸãã
- ã³ãã³ãã€ã³ãžã§ã¯ã·ã§ã³ïŒæ»æè ããµãŒããŒäžã§ä»»æã®ã³ãã³ããå®è¡ããŸãã
- ãã¹ãã©ããŒãµã«ïŒæ»æè ãäžæ£ãªãã¡ã€ã«ããã£ã¬ã¯ããªã«ã¢ã¯ã»ã¹ããŸãã
广çãªå ¥åãµãã¿ã€ãºã¯ãã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠåŠçããããã¹ãŠã®ããŒã¿ãæåŸ ããã圢åŒã«æºæ ããæå®³ãªã³ã³ãã³ããå«ãŸãªãããšãä¿èšŒããããšã§ããããã®ãªã¹ã¯ã軜æžããŸãã
å ¥åãµãã¿ã€ãºã®ããã®TypeScriptã®åã·ã¹ãã æŽ»çš
TypeScriptã®åã·ã¹ãã ã¯ãå ¥åãµãã¿ã€ãºãå®è£ ããäžã§ããã€ãã®å©ç¹ãæäŸããŸãã
- éçè§£æïŒTypeScriptã®ã³ã³ãã€ã©ã¯ãå®è¡æããåã®éçºäžã«æœåšçãªåé¢é£ã®ãšã©ãŒãæ€åºã§ããŸãã
- åå®å šæ§ïŒããŒã¿åã匷å¶ããäºæããªãããŒã¿åœ¢åŒã®ãªã¹ã¯ã軜æžããŸãã
- ã³ãŒãã®æçæ§ïŒæç€ºçãªå宣èšã«ãããã³ãŒãã®å¯èªæ§ãšä¿å®æ§ãåäžãããŸãã
- ãªãã¡ã¯ã¿ãªã³ã°ã®ãµããŒãïŒåå®å šæ§ãç¶æããªãããã³ãŒãã®ãªãã¡ã¯ã¿ãªã³ã°ã容æã«ããŸãã
TypeScriptã®åã·ã¹ãã ãæŽ»çšããããšã§ãéçºè ã¯ã»ãã¥ãªãã£è匱æ§ã®ãªã¹ã¯ãæå°éã«æããå ç¢ãªå ¥åãµãã¿ã€ãºã¡ã«ããºã ãäœæã§ããŸãã
TypeScriptã«ãããäžè¬çãªå ¥åãµãã¿ã€ãºåãã¿ãŒã³
1. æååã®ãµãã¿ã€ãº
æååã®ãµãã¿ã€ãºã«ã¯ãXSSããã®ä»ã®ã€ã³ãžã§ã¯ã·ã§ã³æ»æãé²ãããã«æååå ¥åãã¯ãªãŒã³ã¢ããããã³æ€èšŒããããšãå«ãŸããŸããããã€ãã®äžè¬çãªææ³ã以äžã«ç€ºããŸãã
a. HTMLãšã³ãã£ãã£ã®ãšã¹ã±ãŒã
HTMLãšã³ãã£ãã£ã®ãšã¹ã±ãŒãã¯ãæœåšçã«æå®³ãªæåã察å¿ããHTMLãšã³ãã£ãã£ã«å€æããHTMLã³ãŒããšããŠè§£éãããã®ãé²ããŸããããšãã°ã< 㯠< ã«ã> 㯠> ã«ãªããŸãã
äŸïŒ
function escapeHtml(str: string): string {
const map: { [key: string]: string } = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return str.replace(/[&<>\"']/g, (m) => map[m]);
}
const userInput: string = '';
const sanitizedInput: string = escapeHtml(userInput);
console.log(sanitizedInput); // Output: <script>alert("XSS");</script>
b. æ£èŠè¡šçŸã«ããããªããŒã·ã§ã³
æ£èŠè¡šçŸã¯ãã¡ãŒã«ã¢ãã¬ã¹ãé»è©±çªå·ãªã©ãæååãç¹å®ã®åœ¢åŒã«æºæ ããŠããããšãæ€èšŒããããã«äœ¿çšã§ããŸãã
äŸïŒ
function isValidEmail(email: string): boolean {
const emailRegex: RegExp = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
return emailRegex.test(email);
}
const email1: string = 'test@example.com';
const email2: string = 'invalid-email';
console.log(isValidEmail(email1)); // Output: true
console.log(isValidEmail(email2)); // Output: false
c. ç¹å®ã®æåå圢åŒã®ããã®åãšã€ãªã¢ã¹
TypeScriptã®åãšã€ãªã¢ã¹ã¯ãç¹å®ã®æåå圢åŒãå®çŸ©ããã³ã³ãã€ã«æã«ãããã匷å¶ããããã«äœ¿çšã§ããŸãã
äŸïŒ
type Email = string & { readonly __email: unique symbol };
function createEmail(input: string): Email {
if (!isValidEmail(input)) {
throw new Error('Invalid email format');
}
return input as Email;
}
try {
const validEmail: Email = createEmail('test@example.com');
console.log(validEmail); // Output: test@example.com (with type Email)
const invalidEmail = createEmail('invalid-email'); //Throws error
} catch (error) {
console.error(error);
}
2. æ°å€ã®ãµãã¿ã€ãº
æ°å€ã®ãµãã¿ã€ãºã«ã¯ãæ°å€å ¥åã蚱容ç¯å²å ã«ãããäºæããã圢åŒã«æºæ ããŠããããšãæ€èšŒããããšãå«ãŸããŸãã
a. ç¯å²ããªããŒã·ã§ã³
æ°å€ãç¹å®ã®ç¯å²å ã«ããããšã確èªããŸãã
äŸïŒ
function validateAge(age: number): number {
if (age < 0 || age > 120) {
throw new Error('Invalid age: Age must be between 0 and 120.');
}
return age;
}
try {
const validAge: number = validateAge(30);
console.log(validAge); // Output: 30
const invalidAge: number = validateAge(150); // Throws error
} catch (error) {
console.error(error);
}
b. æ°å€åã®ããã®åã¬ãŒã
å€ã«å¯ŸããŠæäœãå®è¡ããåã«ããã®å€ãæ°å€ã§ããããšã確èªããããã«åã¬ãŒãã䜿çšããŸãã
äŸïŒ
function isNumber(value: any): value is number {
return typeof value === 'number' && isFinite(value);
}
function processNumber(value: any): number {
if (!isNumber(value)) {
throw new Error('Invalid input: Input must be a number.');
}
return value;
}
try {
const validNumber: number = processNumber(42);
console.log(validNumber); // Output: 42
const invalidNumber: number = processNumber('not a number'); // Throws error
} catch (error) {
console.error(error);
}
3. æ¥ä»ã®ãµãã¿ã€ãº
æ¥ä»ã®ãµãã¿ã€ãºã«ã¯ãæ¥ä»å ¥åãæ£ãã圢åŒã§ããã蚱容ç¯å²å ã«ããããšãæ€èšŒããããšãå«ãŸããŸãã
a. æ¥ä»åœ¢åŒã®ããªããŒã·ã§ã³
æ£èŠè¡šçŸãŸãã¯æ¥ä»è§£æã©ã€ãã©ãªã䜿çšããŠãæ¥ä»æååãç¹å®ã®åœ¢åŒïŒäŸïŒYYYY-MM-DDïŒã«æºæ ããŠããããšã確èªããŸãã
äŸïŒ
function isValidDate(dateString: string): boolean {
const dateRegex: RegExp = /^\d{4}-\d{2}-\d{2}$/;
if (!dateRegex.test(dateString)) {
return false;
}
const date: Date = new Date(dateString);
return !isNaN(date.getTime());
}
function parseDate(dateString: string): Date {
if (!isValidDate(dateString)) {
throw new Error('Invalid date format: Date must be in YYYY-MM-DD format.');
}
return new Date(dateString);
}
try {
const validDate: Date = parseDate('2023-10-27');
console.log(validDate); // Output: Fri Oct 27 2023 00:00:00 GMT+0000 (Coordinated Universal Time)
const invalidDate: Date = parseDate('2023/10/27'); // Throws error
} catch (error) {
console.error(error);
}
b. æ¥ä»ç¯å²ã®ããªããŒã·ã§ã³
éå§æ¥ãšçµäºæ¥ãªã©ãæ¥ä»ãç¹å®ã®ç¯å²å ã«ããããšã確èªããŸãã
äŸïŒ
function isDateWithinRange(date: Date, startDate: Date, endDate: Date): boolean {
return date >= startDate && date <= endDate;
}
function validateDateRange(dateString: string, startDateString: string, endDateString: string): Date {
const date: Date = parseDate(dateString);
const startDate: Date = parseDate(startDateString);
const endDate: Date = parseDate(endDateString);
if (!isDateWithinRange(date, startDate, endDate)) {
throw new Error('Invalid date: Date must be between the start and end dates.');
}
return date;
}
try {
const validDate: Date = validateDateRange('2023-10-27', '2023-01-01', '2023-12-31');
console.log(validDate); // Output: Fri Oct 27 2023 00:00:00 GMT+0000 (Coordinated Universal Time)
const invalidDate: Date = validateDateRange('2024-01-01', '2023-01-01', '2023-12-31'); // Throws error
} catch (error) {
console.error(error);
}
4. é åã®ãµãã¿ã€ãº
é åã®ãµãã¿ã€ãºã«ã¯ãé åå ã®èŠçŽ ãç¹å®ã®åºæºãæºãããŠããããšãæ€èšŒããããšãå«ãŸããŸãã
a. é åèŠçŽ ã®ããã®åã¬ãŒã
åã¬ãŒãã䜿çšããŠãé åå ã®åèŠçŽ ãæåŸ ãããåã§ããããšã確èªããŸãã
äŸïŒ
function isStringArray(arr: any[]): arr is string[] {
return arr.every((item) => typeof item === 'string');
perif (typeof item === 'string');
}
function processStringArray(arr: any[]): string[] {
if (!isStringArray(arr)) {
throw new Error('Invalid input: Array must contain only strings.');
}
return arr;
}
try {
const validArray: string[] = processStringArray(['apple', 'banana', 'cherry']);
console.log(validArray); // Output: [ 'apple', 'banana', 'cherry' ]
const invalidArray: string[] = processStringArray(['apple', 123, 'cherry']); // Throws error
} catch (error) {
console.error(error);
}
b. é åèŠçŽ ã®ãµãã¿ã€ãº
ã€ã³ãžã§ã¯ã·ã§ã³æ»æãé²ãããã«ãé åå ã®åèŠçŽ ã«ãµãã¿ã€ãºææ³ãé©çšããŸãã
äŸïŒ
function sanitizeStringArray(arr: string[]): string[] {
return arr.map(escapeHtml);
}
const inputArray: string[] = ['', 'normal text'];
const sanitizedArray: string[] = sanitizeStringArray(inputArray);
console.log(sanitizedArray);
// Output: [ '<script>alert("XSS");</script>', 'normal text' ]
5. ãªããžã§ã¯ãã®ãµãã¿ã€ãº
ãªããžã§ã¯ãã®ãµãã¿ã€ãºã«ã¯ããªããžã§ã¯ãã®ããããã£ãç¹å®ã®åºæºãæºãããŠããããšãæ€èšŒããããšãå«ãŸããŸãã
a. ãªããžã§ã¯ãããããã£ã®åã¢ãµãŒã·ã§ã³
ãªããžã§ã¯ãããããã£ã®åã匷å¶ããããã«åã¢ãµãŒã·ã§ã³ã䜿çšããŸãã
äŸïŒ
interface User {
name: string;
age: number;
email: Email;
}
function validateUser(user: any): User {
if (typeof user.name !== 'string') {
throw new Error('Invalid user: Name must be a string.');
}
if (typeof user.age !== 'number') {
throw new Error('Invalid user: Age must be a number.');
}
if (typeof user.email !== 'string' || !isValidEmail(user.email)) {
throw new Error('Invalid user: Email must be a valid email address.');
}
return {
name: user.name,
age: user.age,
email: createEmail(user.email)
};
}
try {
const validUser: User = validateUser({
name: 'John Doe',
age: 30,
email: 'john.doe@example.com',
});
console.log(validUser);
// Output: { name: 'John Doe', age: 30, email: [Email: john.doe@example.com] }
const invalidUser: User = validateUser({
name: 'John Doe',
age: '30',
email: 'invalid-email',
}); // Throws error
} catch (error) {
console.error(error);
}
b. ãªããžã§ã¯ãããããã£ã®ãµãã¿ã€ãº
ã€ã³ãžã§ã¯ã·ã§ã³æ»æãé²ãããã«ããªããžã§ã¯ãã®åããããã£ã«ãµãã¿ã€ãºææ³ãé©çšããŸãã
äŸïŒ
interface Product {
name: string;
description: string;
price: number;
}
function sanitizeProduct(product: Product): Product {
return {
name: escapeHtml(product.name),
description: escapeHtml(product.description),
price: product.price,
};
}
const inputProduct: Product = {
name: '',
description: 'This is a product description with some HTML.',
price: 99.99,
};
const sanitizedProduct: Product = sanitizeProduct(inputProduct);
console.log(sanitizedProduct);
// Output: { name: '<script>alert("XSS");</script>', description: 'This is a product description with some <b>HTML</b>.', price: 99.99 }
TypeScriptã«ãããå ¥åãµãã¿ã€ãºã®ãã¹ããã©ã¯ãã£ã¹
- æ©æã®ãµãã¿ã€ãºïŒå ¥åãœãŒã¹ã«ã§ããã ãè¿ãå Žæã§ããŒã¿ããµãã¿ã€ãºããŸãã
- å€å±€é²åŸ¡ã¢ãããŒãã䜿çšããïŒå ¥åãµãã¿ã€ãºããåºåãšã³ã³ãŒãã£ã³ã°ããã©ã¡ãŒã¿åãããã¯ãšãªãªã©ã®ä»ã®ã»ãã¥ãªãã£å¯Ÿçãšçµã¿åãããŸãã
- ãµãã¿ã€ãºããžãã¯ãææ°ã®ç¶æ ã«ä¿ã€ïŒææ°ã®ã»ãã¥ãªãã£è匱æ§ã«ã€ããŠåžžã«æ å ±ãåéããããã«å¿ããŠãµãã¿ã€ãºããžãã¯ãæŽæ°ããŸãã
- ãµãã¿ã€ãºããžãã¯ããã¹ãããïŒã€ã³ãžã§ã¯ã·ã§ã³æ»æã广çã«é²ãããšã確å®ã«ããããã«ããµãã¿ã€ãºããžãã¯ã培åºçã«ãã¹ãããŸãã
- 確ç«ãããã©ã€ãã©ãªã䜿çšããïŒè»èŒªã®åçºæãããã®ã§ã¯ãªããäžè¬çãªãµãã¿ã€ãºã¿ã¹ã¯ã«ã¯ãååã«ã¡ã³ããã³ã¹ããä¿¡é ŒãããŠããã©ã€ãã©ãªã掻çšããŸããäŸãã°ãvalidator.jsã®ãããªã©ã€ãã©ãªã®äœ¿çšãæ€èšããŠãã ããã
- ããŒã«ãªãŒãŒã·ã§ã³ãèæ ®ããïŒç°ãªãå°åã®ãŠãŒã¶ãŒå ¥åã«å¯ŸåŠããå Žåãç°ãªãæåã»ãããšãšã³ã³ãŒãã£ã³ã°æšæºïŒäŸïŒUTF-8ïŒã«æ³šæããŠãã ããããšã³ã³ãŒãã£ã³ã°ã®åé¡ã«é¢é£ããè匱æ§ãå°å ¥ããªãããã«ããµãã¿ã€ãºããžãã¯ããããã®ããªãšãŒã·ã§ã³ãæ£ããåŠçããããšã確èªããŠãã ããã
ã°ããŒãã«å ¥åã«é¢ããèæ ®äºé ã®äŸ
ã°ããŒãã«ãªãŠãŒã¶ãŒã察象ãšããã¢ããªã±ãŒã·ã§ã³ãéçºããå Žåã倿§ãªå ¥å圢åŒãšæåçæ £ç¿ãèæ ®ããããšãäžå¯æ¬ ã§ãã以äžã«ããã€ãã®äŸã瀺ããŸãã
- æ¥ä»åœ¢åŒïŒå°åã«ãã£ãŠç°ãªãæ¥ä»åœ¢åŒã䜿çšãããŸãïŒäŸïŒç±³åœã§ã¯MM/DD/YYYYããšãŒãããã§ã¯DD/MM/YYYYïŒãã¢ããªã±ãŒã·ã§ã³ãè€æ°ã®æ¥ä»åœ¢åŒãåŠçããé©åãªããªããŒã·ã§ã³ãæäŸã§ããããšã確èªããŠãã ããã
- æ°å€åœ¢åŒïŒå°åã«ãã£ãŠå°æ°ç¹ãšåã®äœã®åºåãæåãç°ãªããŸãïŒäŸïŒç±³åœã§ã¯1,000.00ããšãŒãããã§ã¯1.000,00ïŒããããã®ããªãšãŒã·ã§ã³ãåŠçããããã«é©åãªè§£æããã³æžåŒèšå®ã©ã€ãã©ãªã䜿çšããŠãã ããã
- é貚èšå·ïŒé貚èšå·ã¯åœã«ãã£ãŠç°ãªããŸãïŒäŸïŒ$ãâ¬ã£ïŒããŠãŒã¶ãŒã®ãã±ãŒã«ã«åºã¥ããŠé貚å€ãæ£ãã衚瀺ããããã«ãé貚æžåŒèšå®ã©ã€ãã©ãªã䜿çšããŠãã ããã
- äœæåœ¢åŒïŒäœæåœ¢åŒã¯åœã«ãã£ãŠå€§ããç°ãªããŸããç°ãªãäœææ§é ã«å¯Ÿå¿ã§ããããã«ãæè»ãªå ¥åãã£ãŒã«ããšããªããŒã·ã§ã³ããžãã¯ãæäŸããŠãã ããã
- åå圢åŒïŒååã®åœ¢åŒã¯æåã«ãã£ãŠç°ãªããŸãïŒäŸïŒè¥¿æŽã®ååã¯éåžžãåã«ç¶ãå§ãæ¥ãŸãããäžéšã®ã¢ãžã¢æåã§ã¯é åºãéã«ãªããŸãïŒããŠãŒã¶ãŒãåžæããååã®é åºãæå®ã§ããããã«ããããšãæ€èšããŠãã ããã
çµè«
å ¥åãµãã¿ã€ãºã¯ãå®å šã§ä¿¡é Œæ§ã®é«ãTypeScriptã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®éèŠãªåŽé¢ã§ããTypeScriptã®åã·ã¹ãã ãæŽ»çšããé©åãªãµãã¿ã€ãºåãã¿ãŒã³ãå®è£ ããããšã§ãéçºè ã¯XSSãã€ã³ãžã§ã¯ã·ã§ã³æ»æãªã©ã®ã»ãã¥ãªãã£è匱æ§ã®ãªã¹ã¯ãå€§å¹ ã«è»œæžã§ããŸããæ©æã«ãµãã¿ã€ãºãè¡ããå€å±€é²åŸ¡ã¢ãããŒãã䜿çšããææ°ã®ã»ãã¥ãªãã£è åšã«ã€ããŠåžžã«æ å ±ãåéããããšãå¿ããªãã§ãã ããããããã®ãã¹ããã©ã¯ãã£ã¹ã«åŸãããšã§ããŠãŒã¶ãŒãšãã®ããŒã¿ãä¿è·ãããããå ç¢ã§å®å šãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸããã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããéã«ã¯ãåžžã«æåçãªæ £ç¿ã念é ã«çœ®ããè¯å¥œãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã確ä¿ããŠãã ããã
ãã®ã¬ã€ãã¯ãTypeScriptã«ãããå ¥åãµãã¿ã€ãºãçè§£ããå®è£ ããããã®ç¢ºåºããåºç€ãæäŸããŸããããããã»ãã¥ãªãã£ã¯åžžã«é²åããåéã§ããã¢ããªã±ãŒã·ã§ã³ã广çã«ä¿è·ããããã«ãåžžã«ææ°ã®ãã¹ããã©ã¯ãã£ã¹ãšè匱æ§ã«é¢ããæ å ±ãå ¥æããŠãã ããã